#include "../common/AuxString.h"
#include "../tinyxml/tinyxml2.h"
#include "../common/AuxFile.h"
#include "Logger.h"

#include <wincon.h>
#include <iostream>
#include <direct.h>


#pragma comment(lib ,"common.lib")


using namespace tinyxml2;

CLogger* CLogger::m_pLogger = NULL;
CLogger::CLogger(void)
{
	ADD_VECTOR_END(m_colors,FOREGROUND_BLUE);
	ADD_VECTOR_END(m_colors,FOREGROUND_INTENSITY);
	ADD_VECTOR_END(m_colors,FOREGROUND_GREEN);
	ADD_VECTOR_END(m_colors,FOREGROUND_RED);

	m_strLogFileDir = CAuxFile::GetAppDir();
	m_strLogFileName = CAuxFile::GetAppName() + ".log";

	m_strConfigFileDir = CAuxFile::GetConfigsDir() + CAuxFile::GetAppName() + '/';
	m_strConfigFileName= CAuxFile::GetAppName() + "_config.xml";
	LoadConfig();
}


CLogger::~CLogger(void)
{
}
CLogger* CLogger::Ins()
{
	if(m_pLogger)
		return m_pLogger;
	else
		return m_pLogger = new CLogger();
}

void CLogger::log(EnumLevel Level,string fileName, int lineNumber,string functionName, string formatString, ...)
{
	char buf[1024];
	va_list va;
	va_start(va,formatString);
	vsprintf_s(buf,formatString.c_str(),va);
	va_end(va);


	bool tofile = Ins()->QueryToFile(Level);
	if(tofile)
	{
		if (!Ins()->m_filestream.is_open())
			Ins()->OpenFile();
		stringstream strLog;
		strLog << fileName << " " << "lineNumber:" << CAuxString::ToString(lineNumber) << " " << functionName << " " << buf << endl;
		Ins()->WriteToFile(strLog.str());
	}

	bool toconsole = Ins()->QueryToConsole(Level);
	if(toconsole)
	{
		Ins()->SetConsoleColor(Ins()->m_colors[Level]);
		cout << fileName<<" "<<"lineNumber:"<<lineNumber<<" "<<functionName<<" "<<endl;
	}
}
void CLogger::log(EnumLevel Level,string formatString, ...)
{

	char buf[1024];
	va_list va;
	va_start(va,formatString);
	vsprintf_s(buf,formatString.c_str(),va);
	va_end(va);

	bool tofile = Ins()->QueryToFile(Level);
	if(tofile)
	{
		if (!Ins()->m_filestream.is_open())
			Ins()->OpenFile();
		Ins()->WriteToFile(string(buf));
	}


	bool toconsole = Ins()->QueryToConsole(Level);
	if(toconsole)
	{
		Ins()->SetConsoleColor(Ins()->m_colors[Level]);
		cout << buf << endl;
	}
}
void CLogger::logHex(EnumLevel Level,string strHex)
{
	static const char hexdig[]="0123456789abcdef";
	unsigned long i;
	char line[50],*ptr;

	ptr=line;

	for(i = 0;i < strHex.length(); i++)
	{
		*ptr++ = hexdig[ 0x0f & (strHex[i] >> 4)];
		*ptr++ = hexdig[ 0x0f & strHex[i] ];
		if(( i & 0x0f ) == 0x0f )
		{
			*ptr = '\0';
			ptr = line;

			bool tofile = Ins()->QueryToFile(Level);
			if(tofile)
				Ins()->WriteToFile(string(line));

			bool toconsole = Ins()->QueryToConsole(Level);
			if(toconsole)
			{
				Ins()->SetConsoleColor(Ins()->m_colors[Level]);
				cout << line << endl;
			}
		}
		else
		{
			*ptr++ = ' ';
		}
	}
	if(i & 0x0f)
	{
		*ptr = '\0';

		bool tofile = Ins()->QueryToFile(Level);
		if(tofile)
			Ins()->WriteToFile(string(line));

		bool toconsole = Ins()->QueryToConsole(Level);
		if(toconsole)
		{
			Ins()->SetConsoleColor(Ins()->m_colors[Level]);
			cout << line << endl;
		}
	}
}
void CLogger::WriteToFile(string formatString)
{
	if (!m_filestream.is_open())
		OpenFile();
	m_filestream << formatString <<endl;

}
void CLogger::SetConsoleColor(WORD color)
{
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),color);
}
bool CLogger::QueryToFile(EnumLevel Level)
{
	for(NoteItem NI:m_NoteItemAttributes)
	{
		if(NI.type == Level)
			return NI.tofile;
	}
	return false;
}

void CLogger::SetToFile(EnumLevel Level,bool tofile)
{
	for(NoteItem NI:m_NoteItemAttributes)
	{
		if(NI.type == Level)
			NI.tofile = tofile;
		break;
	}
}
bool CLogger::QueryToConsole(EnumLevel Level)
{
	for(NoteItem NI:m_NoteItemAttributes)
	{
		if(NI.type == Level)
			return NI.toconsole;
	}
	return false;
}
void CLogger::SetToConsole(EnumLevel Level,bool isconsole)
{
	for(NoteItem NI:m_NoteItemAttributes)
	{
		if(NI.type == Level)
			NI.toconsole = isconsole;
		break;
	}
}
void CLogger::OpenFile()
{
	m_filestream.open(m_strLogFileDir.c_str(),ios::app);
}
void CLogger::LoadConfig()
{
	string filename = m_strConfigFileDir + m_strConfigFileName;

	tinyxml2::XMLDocument	xmlDoc;
	if(xmlDoc.LoadFile(filename.c_str()) != XML_NO_ERROR)
		return;

	XMLElement* xmlrule = NULL;
	xmlrule = xmlDoc.FirstChildElement("rule");
	if(!xmlrule)
		return;

	XMLElement* xmlclause = NULL;
	xmlclause = xmlrule->FirstChildElement("clause");
	const XMLAttribute* xmAttr = NULL;
	while(xmlclause)
	{
		if(NULL == (xmAttr = xmlclause->FirstAttribute()))
			return;

		NoteItem NI; 
		string type = xmAttr->Value();
		if("_LOG_" == type)
			NI.type = _LOG_;
		else if("_WARNING_" == type)
			NI.type = _WARNING_;
		else if("_DEBUG_" == type)
			NI.type = _DEBUG_;
		else if("_ERROR_" == type)
			NI.type = _ERROR_;

		if(NULL == (xmAttr = xmAttr->Next()))
			return;
		if(strcmp("true",xmAttr->Value()) == 0)
			NI.effect = true;

		if(NULL == (xmAttr = xmAttr->Next()))
			return;
		if(strcmp("true",xmAttr->Value()) == 0)
			NI.tofile = true;

		if(NULL == (xmAttr = xmAttr->Next()))
			return;
		if(strcmp("true",xmAttr->Value()) == 0)
			NI.toconsole = true;

		m_NoteItemAttributes.push_back(NI);
		xmlclause = xmlclause->NextSiblingElement();
	}
}
void CLogger::SetLogFileDir(string str)
{
	m_strLogFileDir = str;
}
string CLogger::GetLogFileDir()
{
	return m_strLogFileDir;
}
void CLogger::SetLogFileName(string str)
{
	m_strLogFileName = str;
}
string CLogger::GetLogFileName()
{
	return m_strLogFileName;
}
void CLogger::SetConfigFileDir(string str)
{
	m_strConfigFileDir = str;
}
string CLogger::GetConfigFileDir()
{
	return m_strConfigFileDir;
}
void CLogger::SetConfigFileName(string str)
{
	m_strConfigFileName = str;
}
string CLogger::GetConfigFileName()
{
	return m_strConfigFileName;
}